using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ViewOn.Kernel;
using ViewOn.Helper.WPF.Shader;
using ViewOnCore.Helper.WPF;
using ViewOnCore.HostContract;
using ViewOn.AddInsHostContract.UI;

namespace ViewOn.UI.Control
{
    public delegate void NavigationPanelHandler(FrameworkElement element);

    // HLSL : http://msdn.microsoft.com/fr-fr/library/dd144148.aspx

    public partial class NavigationPanel : System.Windows.Controls.UserControl
    {

        #region Variables

        //---- Settings
        static public Dictionary<string, object> Settings = new Dictionary<string, object>();

        //---- Navigation
        private FrameworkElement _currentElement = null;
        private FrameworkElement _previousElement = null;

        //---- Events
        public event NavigationPanelHandler OnNavigationStarted;
        public event NavigationPanelHandler OnNavigationCompleted;

        #endregion

        #region Constructor

        static NavigationPanel()
        {
            InitializeSettings();
        }

        public NavigationPanel()
        {
            InitializeComponent();

            //---- Set up story boards
            Storyboard storyboard;

            //---- Sliding
            storyboard = (Storyboard)FindResource("slideInVertical");
            ((DoubleAnimation)storyboard.Children[2]).Completed += new EventHandler(NavigationPanel_Completed);

            storyboard = (Storyboard)FindResource("slideInHorizontal");
            ((DoubleAnimation)storyboard.Children[2]).Completed += new EventHandler(NavigationPanel_Completed);

            //---- Smooth sliding
            storyboard = (Storyboard)FindResource("smoothSlideInToLeft");
            storyboard.Completed += new EventHandler(NavigationPanel_Completed);

            storyboard = (Storyboard)FindResource("smoothSlideInToRight");
            storyboard.Completed += new EventHandler(NavigationPanel_Completed);

            storyboard = (Storyboard)FindResource("smoothSlideInToTop");
            storyboard.Completed += new EventHandler(NavigationPanel_Completed);

            storyboard = (Storyboard)FindResource("smoothSlideInToBottom");
            storyboard.Completed += new EventHandler(NavigationPanel_Completed);

            //---- Read the configuration from configuration
            Host.UIService.TransitionKindWithoutShader = (TransitionKindWithoutShader)Enum.Parse(typeof(TransitionKindWithoutShader), Host.SettingsService.TransitionKindWithoutShader);
            Host.UIService.TransitionKindWithShader = (TransitionKindWithShader)Enum.Parse(typeof(TransitionKindWithShader), Host.SettingsService.TransitionKindWithShader);
        }

        #endregion

        #region InitializeSettings

        static private void InitializeSettings()
        {
            //---- Without shader
            if (!Host.UIService.IsShaderSupported)
            {
                Settings.Add(TransitionKindWithoutShader.Sliding.ToString(), new TransitionSettingsSliding());
                Settings.Add(TransitionKindWithoutShader.SmoothSliding.ToString(), new TransitionSettingsSmoothSlide());
            }
            else
            {
                //---- With shader
                Settings.Add(TransitionKindWithShader.Sliding.ToString(), new SlideInTransitionEffect { SlideAmount = new Vector(-0.3, 0) });
                Settings.Add(TransitionKindWithShader.Fade.ToString(), new FadeTransitionEffect());
                Settings.Add(TransitionKindWithShader.Ripple.ToString(), new RippleTransitionEffect());
                Settings.Add(TransitionKindWithShader.Pixelate.ToString(), new PixelateTransitionEffect());
                Settings.Add(TransitionKindWithShader.LineReveal.ToString(), new LineRevealTransitionEffect { LineOrigin = new Vector(-0.2, -0.2), LineNormal = new Vector(1, 0), LineOffset = new Vector(1.4, 0), FuzzyAmount = 0.2 });
            }
        }

        #endregion

        #region Properties

        public UIElementCollection Elements
        {
            get
            {
                return elementsContainer.Children;
            }
        }

        public FrameworkElement CurrentElement
        {
            get
            {
                return _currentElement;
            }
        }

        #endregion

        #region AddElement

        public void AddUIElement(string key, FrameworkElement element)
        {
            element.Name = key;
            element.Visibility = Visibility.Collapsed;
            elementsContainer.Children.Add(element);
        }

        #endregion

        #region NavigateBack

        public void NavigateBack()
        {
            InverseAnimationDirection();
            Navigate(_previousElement);
            InverseAnimationDirection();
        }

        #endregion

        #region InverseAnimationDirection

        public void InverseAnimationDirection()
        {
            if (Host.UIService.IsShaderSupported)
                return;

            if (Host.UIService.TransitionKindWithoutShader == TransitionKindWithoutShader.Sliding)
            {
                TransitionSettingsSliding settings = (TransitionSettingsSliding)Settings[Host.UIService.TransitionKindWithoutShader.ToString()];
                if (settings.Direction == TransitionDirection.ToTop)
                    settings.Direction = TransitionDirection.ToBottom;
                else if (settings.Direction == TransitionDirection.ToBottom)
                    settings.Direction = TransitionDirection.ToTop;
                else if (settings.Direction == TransitionDirection.ToLeft)
                    settings.Direction = TransitionDirection.ToRight;
                else if (settings.Direction == TransitionDirection.ToRight)
                    settings.Direction = TransitionDirection.ToLeft;
                return;
            }

            if (Host.UIService.TransitionKindWithoutShader == TransitionKindWithoutShader.SmoothSliding)
            {
                TransitionSettingsSmoothSlide settings = (TransitionSettingsSmoothSlide)Settings[Host.UIService.TransitionKindWithoutShader.ToString()];
                if (settings.Direction == TransitionDirection.ToTop)
                    settings.Direction = TransitionDirection.ToBottom;
                else if (settings.Direction == TransitionDirection.ToBottom)
                    settings.Direction = TransitionDirection.ToTop;
                else if (settings.Direction == TransitionDirection.ToLeft)
                    settings.Direction = TransitionDirection.ToRight;
                else if (settings.Direction == TransitionDirection.ToRight)
                    settings.Direction = TransitionDirection.ToLeft;
                return;
            }
        }

        #endregion

        #region FindElement

        public FrameworkElement FindElement(string key)
        {
            foreach (FrameworkElement element in elementsContainer.Children)
                if (element.Name == key)
                    return element;

            return null;
        }

        #endregion

        #region Navigate

        public void Navigate(FrameworkElement element)
        {
            if (_currentElement == element)
                return;

            if (Host.UIService.IsShaderSupported)
                NavigateWithShader(element);
            else
                NavigateWithoutShader(element);
        }

        #endregion

        #region Navigation completed

        void NavigationPanel_Completed(object sender, EventArgs e)
        {
            System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(Completed));
        }

        private void Completed(object target)
        {
            System.Threading.Thread.Sleep(100);

            Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Send,
                (DelegateInvoker)delegate
                {
                    if (OnNavigationCompleted != null)
                        OnNavigationCompleted(_currentElement);
                });
        }

        #endregion

        #region No shader : NavigateWithoutShader

        private void NavigateWithoutShader(FrameworkElement element)
        {
            //---- Prepare the user control
            TransformGroup transformGroup = new TransformGroup();
            transformGroup.Children.Add(new ScaleTransform(1, 1));
            transformGroup.Children.Add(new RotateTransform(0));
            transformGroup.Children.Add(new TranslateTransform(0, 0));

            element.RenderTransform = transformGroup;

            //---- Notification
            if (OnNavigationStarted != null)
                OnNavigationStarted(element);

            //---- First animation
            if (_currentElement != null)
            {
                switch (Host.UIService.TransitionKindWithoutShader)
                {
                    case TransitionKindWithoutShader.Sliding:
                        SlideOutView(_currentElement);
                        break;
                    case TransitionKindWithoutShader.SmoothSliding:
                        SmoothSlideOutView(_currentElement);
                        break;
                }
            }

            //---- Set new settings
            _previousElement = _currentElement;
            _currentElement = element;

            //---- Second animation
            if (_currentElement != null)
            {
                switch (Host.UIService.TransitionKindWithoutShader)
                {
                    case TransitionKindWithoutShader.Sliding:
                        SlideInView(_currentElement);
                        break;
                    case TransitionKindWithoutShader.SmoothSliding:
                        SmoothSlideInView(_currentElement);
                        break;
                }
            }
        }

        #endregion

        #region No shader : Slide out

        private void SlideOutView(FrameworkElement part)
        {
            TransitionSettingsSliding settings = (TransitionSettingsSliding)Settings[TransitionKindWithoutShader.Sliding.ToString()];

            if (settings.Direction == TransitionDirection.ToTop)
                SlideOutToTop(part);
            else if (settings.Direction == TransitionDirection.ToBottom)
                SlideOutToBottom(part);
            else if (settings.Direction == TransitionDirection.ToLeft)
                SlideOutToLeft(part);
            else if (settings.Direction == TransitionDirection.ToRight)
                SlideOutToRight(part);
        }

        #endregion

        #region No shader : Slide in

        private void SlideInView(FrameworkElement part)
        {
            TransitionSettingsSliding settings = (TransitionSettingsSliding)Settings[TransitionKindWithoutShader.Sliding.ToString()];

            if (settings.Direction == TransitionDirection.ToTop)
                SlideInToTop(part);
            else if (settings.Direction == TransitionDirection.ToBottom)
                SlideInToBottom(part);
            else if (settings.Direction == TransitionDirection.ToLeft)
                SlideInToLeft(part);
            else if (settings.Direction == TransitionDirection.ToRight)
                SlideInToRight(part);
        }

        #endregion

        #region No shader : Slinding : to top

        private void SlideOutToTop(FrameworkElement part)
        {
            //---- Set up the storyboard
            Storyboard storyboard = FindResource("slideOutVertical") as Storyboard;
            DoubleAnimation animation = storyboard.Children[2] as DoubleAnimation;
            animation.From = new double?(0);
            animation.To = new double?(ActualHeight * -1);

            //---- Start the animation
            part.BeginAnimation(UIElement.RenderTransformProperty, null);
            storyboard.Begin(part);
        }

        private void SlideInToTop(FrameworkElement part)
        {
            //---- Set up the storyboard
            Storyboard storyboard = FindResource("slideInVertical") as Storyboard;

            DoubleAnimation animation = storyboard.Children[2] as DoubleAnimation;
            animation.From = new double?(ActualHeight);
            animation.To = new double?(10);

            animation = storyboard.Children[3] as DoubleAnimation;
            animation.From = new double?(10);
            animation.To = new double?(0);

            //---- Start the animation
            part.BeginAnimation(UIElement.RenderTransformProperty, null);
            storyboard.Begin(part);
        }

        #endregion

        #region No shader : Slinding : to bottom

        private void SlideOutToBottom(FrameworkElement part)
        {
            //---- Set up the storyboard
            Storyboard storyboard = FindResource("slideOutVertical") as Storyboard;
            DoubleAnimation animation = storyboard.Children[2] as DoubleAnimation;
            animation.From = new double?(0);
            animation.To = new double?(ActualHeight);

            //---- Start the animation
            part.BeginAnimation(UIElement.RenderTransformProperty, null);
            storyboard.Begin(part);
        }

        private void SlideInToBottom(FrameworkElement part)
        {
            //---- Set up the storyboard
            Storyboard storyboard = FindResource("slideInVertical") as Storyboard;

            DoubleAnimation animation = storyboard.Children[2] as DoubleAnimation;
            animation.From = new double?(ActualHeight * -1);
            animation.To = new double?(-10);

            animation = storyboard.Children[3] as DoubleAnimation;
            animation.From = new double?(-10);
            animation.To = new double?(0);

            //---- Start the animation
            part.BeginAnimation(UIElement.RenderTransformProperty, null);
            storyboard.Begin(part);
        }

        #endregion

        #region No shader : Slinding : to left

        private void SlideOutToLeft(FrameworkElement part)
        {
            //---- Set up the storyboard
            Storyboard storyboard = FindResource("slideOutHorizontal") as Storyboard;
            DoubleAnimation animation = storyboard.Children[2] as DoubleAnimation;
            animation.From = new double?(0);
            animation.To = new double?(ActualWidth * -1);

            //---- Start the animation
            part.BeginAnimation(UIElement.RenderTransformProperty, null);
            storyboard.Begin(part);
        }

        private void SlideInToLeft(FrameworkElement part)
        {
            //---- Set up the storyboard
            Storyboard storyboard = FindResource("slideInHorizontal") as Storyboard;

            DoubleAnimation animation = storyboard.Children[2] as DoubleAnimation;
            animation.From = new double?(ActualWidth);
            animation.To = new double?(10);

            animation = storyboard.Children[3] as DoubleAnimation;
            animation.From = new double?(10);
            animation.To = new double?(0);

            //---- Start the animation
            part.BeginAnimation(UIElement.RenderTransformProperty, null);
            storyboard.Begin(part);
        }

        #endregion

        #region No shader : Slinding : to right

        private void SlideOutToRight(FrameworkElement part)
        {
            //---- Set up the storyboard
            Storyboard storyboard = FindResource("slideOutHorizontal") as Storyboard;
            DoubleAnimation animation = storyboard.Children[2] as DoubleAnimation;
            animation.From = new double?(0);
            animation.To = new double?(ActualWidth);

            //---- Start the animation
            part.BeginAnimation(UIElement.RenderTransformProperty, null);
            storyboard.Begin(part);
        }

        private void SlideInToRight(FrameworkElement part)
        {
            //---- Set up the storyboard
            Storyboard storyboard = FindResource("slideInHorizontal") as Storyboard;

            DoubleAnimation animation = storyboard.Children[2] as DoubleAnimation;
            animation.From = new double?(ActualWidth * -1);
            animation.To = new double?(-10);

            animation = storyboard.Children[3] as DoubleAnimation;
            animation.From = new double?(-10);
            animation.To = new double?(0);

            //---- Start the animation
            part.BeginAnimation(UIElement.RenderTransformProperty, null);
            storyboard.Begin(part);
        }

        #endregion

        #region No shader : Smooth Slide out

        private void SmoothSlideOutView(FrameworkElement part)
        {
            Storyboard storyboard = FindResource("smoothSlideOut") as Storyboard;
            storyboard.Begin(part, false);
        }

        #endregion

        #region No shader : Smooth Slide in

        private void SmoothSlideInView(FrameworkElement part)
        {
            TransitionSettingsSmoothSlide settings = (TransitionSettingsSmoothSlide)Settings[TransitionKindWithoutShader.SmoothSliding.ToString()];

            if (settings.Direction == TransitionDirection.ToBottom)
                SmoothSlideInToBottom(part);
            else if (settings.Direction == TransitionDirection.ToTop)
                SmoothSlideInToTop(part);
            else if (settings.Direction == TransitionDirection.ToLeft)
                SmoothSlideInToLeft(part);
            else if (settings.Direction == TransitionDirection.ToRight)
                SmoothSlideInToRight(part);
        }

        #endregion

        #region No shader : Smooth Sliding : to right

        private void SmoothSlideInToRight(FrameworkElement part)
        {
            //---- Set up the storyboard
            Storyboard storyboard = FindResource("smoothSlideInToRight") as Storyboard;
            storyboard.Begin(part, false);
        }

        #endregion

        #region No shader : Smooth Sliding : to left

        private void SmoothSlideInToLeft(FrameworkElement part)
        {
            //---- Set up the storyboard
            Storyboard storyboard = FindResource("smoothSlideInToLeft") as Storyboard;
            storyboard.Begin(part);
        }

        #endregion

        #region No shader : Smooth Sliding : to top

        private void SmoothSlideInToTop(FrameworkElement part)
        {
            //---- Set up the storyboard
            Storyboard storyboard = FindResource("smoothSlideInToTop") as Storyboard;
            storyboard.Begin(part);
        }

        #endregion

        #region No shader : Smooth Sliding : to bottom

        private void SmoothSlideInToBottom(FrameworkElement part)
        {
            //---- Set up the storyboard
            Storyboard storyboard = FindResource("smoothSlideInToBottom") as Storyboard;
            storyboard.Begin(part);
        }

        #endregion

        #region No shader : Blur in

        private void BlurIn(FrameworkElement element)
        {
            element.Visibility = Visibility.Visible;

            //---- Create the blur effect
            BlurBitmapEffect effect = new BlurBitmapEffect();
            effect.KernelType = KernelType.Box;
            effect.Radius = 8.0;

            element.BitmapEffect = effect;

            //---- Add the animation
            DoubleAnimation animation = new DoubleAnimation();
            animation.From = 8.0;
            animation.To = 0.0;
            animation.Duration = new Duration(TimeSpan.FromMilliseconds(250));

            DoubleAnimation animation2 = new DoubleAnimation();
            animation2.From = 0.0;
            animation2.To = 1.0;
            animation2.Duration = new Duration(TimeSpan.FromMilliseconds(250));

            element.BitmapEffect.BeginAnimation(BlurBitmapEffect.RadiusProperty, animation);
            element.BeginAnimation(UIElement.OpacityProperty, animation2);
        }

        #endregion

        #region No shader : Blur out

        private void BlurOut(FrameworkElement element)
        {
            //---- Create the blur effect
            BlurBitmapEffect effect = new BlurBitmapEffect();
            effect.KernelType = KernelType.Box;
            effect.Radius = 8.0;

            element.BitmapEffect = effect;

            //---- Add the animation
            DoubleAnimation animation = new DoubleAnimation();
            animation.From = 0.0;
            animation.To = 8.0;
            animation.Duration = new Duration(TimeSpan.FromMilliseconds(250));

            DoubleAnimation animation2 = new DoubleAnimation();
            animation2.From = 1.0;
            animation2.To = 0.0;
            animation2.Duration = new Duration(TimeSpan.FromMilliseconds(250));

            element.BitmapEffect.BeginAnimation(BlurBitmapEffect.RadiusProperty, animation);
            element.BeginAnimation(UIElement.OpacityProperty, animation2);
            animation.Completed += new EventHandler(animation_Completed);
        }

        void animation_Completed(object sender, EventArgs e)
        {
            _previousElement.Visibility = Visibility.Collapsed;
        }



        //private bool FadeIn()
        //{
        //    bool flag;
        //    DoubleAnimation animation = new DoubleAnimation();
        //    DoubleAnimation animation2 = animation;
        //    animation2.From = 0.0;
        //    animation2.To = 1.0;
        //    Duration duration = new Duration(TimeSpan.FromMilliseconds((double)this.mDuration));
        //    animation2.Duration = duration;
        //    animation2 = null;
        //    this.BeginAnimation(UIElement.OpacityProperty, animation);
        //    return flag;
        //}

        //private bool FadeOut()
        //{
        //    bool flag;
        //    DoubleAnimation animation = new DoubleAnimation();
        //    DoubleAnimation animation2 = animation;
        //    animation2.From = 1.0;
        //    animation2.To = 0.0;
        //    Duration duration = new Duration(TimeSpan.FromMilliseconds((double)this.mDuration));
        //    animation2.Duration = duration;
        //    animation2 = null;
        //    this.BeginAnimation(UIElement.OpacityProperty, animation);
        //    return flag;
        //}

        #endregion

        #region With shader : NavigateWithShader

        private void NavigateWithShader(FrameworkElement element)
        {
            //---- Notification
            if (OnNavigationStarted != null)
                OnNavigationStarted(element);

            //---- Set new settings
            _previousElement = _currentElement;
            _currentElement = element;

            //--- Choose the right transition
            TransitionEffect effect = null;
            DoubleAnimation animation = null;

            switch (Host.UIService.TransitionKindWithShader)
            {
                case TransitionKindWithShader.Sliding:
                    effect = new SlideInTransitionEffect { SlideAmount = new Vector(-1, 0) };
                    animation = new DoubleAnimation(0.4, 1.0, new Duration(TimeSpan.FromSeconds(0.5)), FillBehavior.HoldEnd);
                    animation.AccelerationRatio = 0.7;
                    animation.DecelerationRatio = 0.3;
                    break;
                case TransitionKindWithShader.Fade:
                    effect = new FadeTransitionEffect();
                    break;
                case TransitionKindWithShader.Ripple:
                    effect = new RippleTransitionEffect();
                    break;
                case TransitionKindWithShader.Pixelate:
                    effect = new PixelateTransitionEffect();
                    //effect = new PixelateInTransitionEffect();
                    //effect = new PixelateOutTransitionEffect();
                    break;
                case TransitionKindWithShader.LineReveal:
                    effect = new LineRevealTransitionEffect { LineOrigin = new Vector(-0.2, -0.2), LineNormal = new Vector(1, 0), LineOffset = new Vector(1.4, 0), FuzzyAmount = 0.2 };
                    break;
            }

            //---- Default animation
            if (animation == null)
            {
                animation = new DoubleAnimation(0, 1.0, new Duration(TimeSpan.FromSeconds(0.5)), FillBehavior.HoldEnd);
                animation.AccelerationRatio = 0.7;
                animation.DecelerationRatio = 0.3;
            }

            //effect = new WaveTransitionEffect();
            //effect = new CircularBlurTransitionEffect();
            //effect = new MostBrightTransitionEffect();
            //effect = new ShrinkTransitionEffect();
            //effect = new RadialBlurTransitionEffect();

            Transition(element, effect, animation);
        }

        private void Transition(FrameworkElement element, TransitionEffect effect, DoubleAnimation transitionAnimation)
        {
            //---- Show the current one
            VisualBrush vb = null;
            if (_previousElement != null)
            {
                vb = new VisualBrush(_previousElement);
                vb.Viewbox = new Rect(0, 0, _previousElement.ActualWidth, _previousElement.ActualHeight);
                vb.ViewboxUnits = BrushMappingMode.Absolute;
            }

            // Apply the animation
            transitionAnimation.Completed += new EventHandler(transitionAnimation_Completed);
            effect.BeginAnimation(TransitionEffect.ProgressProperty, transitionAnimation);

            if (vb != null)
                effect.OldImage = vb;
            _currentElement.Effect = effect;
            _currentElement.Visibility = Visibility.Visible;

            //((TranslateTransform)((TransformGroup )_previousElement.RenderTransform).Children[2]).X = _previousElement.ActualWidth;
            if (_previousElement != null)
                _previousElement.Visibility = Visibility.Hidden;
        }

        void transitionAnimation_Completed(object sender, EventArgs e)
        {
            if (_previousElement != null)
                _previousElement.Visibility = Visibility.Collapsed;
            //((TranslateTransform)((TransformGroup)_previousElement.RenderTransform).Children[2]).X = 0;
            _currentElement.Effect = null;

            NavigationPanel_Completed(sender, e);
        }

        #endregion

    }


    #region TransitionSettings

    public class TransitionSettings
    {
    }

    public enum TransitionDirection
    {
        ToTop,
        ToBottom,
        ToLeft,
        ToRight
    }

    public class TransitionSettingsSliding : TransitionSettings
    {
        public TransitionDirection Direction = TransitionDirection.ToRight;
    }

    public class TransitionSettingsSmoothSlide : TransitionSettings
    {
        public TransitionDirection Direction = TransitionDirection.ToRight;
    }

    #endregion

}